extern crate html5ever;
#[macro_use] extern crate lazy_static;
extern crate rayon;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
extern crate tendril;

use rayon::prelude::*;
use tendril::TendrilSink;

#[derive(Deserialize)]
struct Node {
    pub content: Option<String>,
    pub nodes: Vec<Node>,
    pub title: Option<String>
}

lazy_static! {
    static ref COND1: Vec<&'static str> = vec!["Jesus", "Christ", "He", "His", "Lord"];
    static ref COND2: Vec<&'static str> = vec!["said", "sayeth", "saith", "word", "Word", "spake", "spoke"];
}

fn extract_text(node: &html5ever::rcdom::Node) -> Vec<String> {
    let mut text = match node.data {
        html5ever::rcdom::NodeData::Text { ref contents } => {
            vec![(**contents.borrow()).to_owned()]
        },
        html5ever::rcdom::NodeData::Element { ref name, .. } => {
            if &name.local == "sup" {
                return vec![];
            }
            vec![]
        },
        _ => {
            vec![]
        }
    };
    for child in node.children.borrow().iter() {
        text.append(&mut extract_text(child));
    }
    text
}

fn clean_html(data: &str) -> String {
    let dom = html5ever::parse_document(html5ever::rcdom::RcDom::default(), html5ever::ParseOpts::default())
        .from_utf8()
        .one(data.as_bytes());
    let document = dom.document;
    extract_text(&document).join(" ")
}

fn process_node(node: &Node, parents: &str) {
    let new_parents = format!("{} {}", parents, match node.title {
        Some(ref title) => title,
        None => ""
    });
    node.nodes.par_iter()
        .for_each(|x| process_node(x, &new_parents));
    if let Some(ref content) = node.content {
        for versedata in content.split("<div ") {
            let versedata = format!("<div {}", versedata);
            let text = clean_html(&versedata);
            let mut found1: Option<usize> = None;
            let mut found2: Option<usize> = None;
            for word in COND1.iter() {
                if let Some(pos) = text.find(word) {
                    found1 = Some(pos);
                    break;
                }
            }
            if let Some(start) = found1 {
                for word in COND2.iter() {
                    if let Some(pos) = text[start..].find(word) {
                        found2 = Some(pos);
                        break;
                    }
                }
                if found2.is_some() {
                    println!("{} {}", &new_parents, text);
                }
            }
        }
    }
}

fn main() {
    let file = std::fs::File::open(std::env::args().nth(1).expect("Missing book file")).expect("Failed to open file");
    eprintln!("loading data");
    let data: Node = serde_json::from_reader(file).expect("Failed to parse nodes");
    eprintln!("finished loading data");
    eprintln!("start processing");
    process_node(&data, "");
}
